module dgl.Game;

import tango.stdc.stringz;

import derelict.sdl.sdl;
import derelict.sdl.image;
import derelict.util.exception;
import derelict.opengl.gl;
import derelict.opengl.glu;

import dgl.GameTime;
import dgl.GameWindow;
import dgl.content.ContentManager;
import dgl.graphics.SpriteBatch;
import dgl.Vector2;
import dgl.Vector4;
import dgl.graphics.Color;
import dgl.input.MouseMessageHooker;

class Game
{
	private GameWindow m_window;
	
	private uint m_oldSDLTime;
	
	private float m_totalTime;
	
	private bool m_isRunning;
	
	private SpriteBatch m_spriteBatch;
	
	this()
	{
		m_window = new GameWindow();
		m_oldSDLTime = 0;
		m_totalTime = 0.0f;
		m_isRunning = false;
		
		DerelictSDL.load();
		DerelictGL.load();
		DerelictGLU.load();
		DerelictSDLImage.load();
		
		SDL_Init( SDL_INIT_VIDEO | SDL_INIT_TIMER );
		SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
		
		SDL_SetVideoMode( m_window.clientBounds.width, m_window.clientBounds.height, 24, SDL_OPENGL );
		SDL_WM_SetCaption( toStringz( m_window.title ), null );
		
		DerelictGL.loadVersions( DerelictGL.availableVersion );
		
		m_oldSDLTime = SDL_GetTicks();
		m_totalTime = 0.0f;
		m_isRunning = true;
		
		
		glEnable( GL_TEXTURE_2D );
		glViewport( 0, 0, m_window.clientBounds.width, m_window.clientBounds.height );
		glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );
		
		glEnable( GL_BLEND );
		glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
		
		Vector4 clearColor = Color.cornflowerBlue.toVector4();
		glClearColor( clearColor.x, clearColor.y, clearColor.z, clearColor.w );
		
		m_spriteBatch = new SpriteBatch( Vector2( m_window.clientBounds.width, m_window.clientBounds.height ) );
	}
	
	public GameWindow window()
	{
		return m_window;
	}
	
	public SpriteBatch spriteBatch()
	{
		return m_spriteBatch;
	}
	
	public void cursorDisplay( bool isDisplayCursor )
	{
		if( isDisplayCursor )
		{
			SDL_ShowCursor( 1 );
		}
		else
		{
			SDL_ShowCursor( 0 );
		}
	}
	
	protected void initialize()
	{
		
	}
	
	protected void loadContent()
	{
		
	}
	
	protected void unloadContent()
	{
		
	}
	
	protected void update( GameTime gameTime )
	{
		
	}
	
	protected void draw( GameTime gameTime )
	{
		
	}
	
	public void run()
	{
		this.initialize();
		this.loadContent();
		
		scope( exit )
		{
			this.unloadContent();
		}
		
		while( true )
		{
			if( m_isRunning == false )
				break;
			
			SDL_Event event;

			// handle all SDL events that we might've received in this loop iteration
			while( SDL_PollEvent( &event ) )
			{
				MouseMessageHooker.processEvent( event );
				switch( event.type )
				{
				case SDL_QUIT:
					m_isRunning = false;
					break;
				default:
					break;
				}
			}
			
			uint curSDLTime = SDL_GetTicks();
			float elapsed = cast(float)( curSDLTime - m_oldSDLTime ) / 1000.0f;
			m_totalTime += elapsed;
			
			GameTime gameTime = new GameTime( m_totalTime, elapsed, m_totalTime, elapsed );

			this.update( gameTime );
			this.draw( gameTime );
			
			m_oldSDLTime = curSDLTime;
			
			SDL_GL_SwapBuffers();
		}
	}
	
	public void exit()
	{
		m_isRunning = false;
		
		SDL_Quit();
		
		DerelictGLU.unload();
		DerelictGL.unload();
		DerelictSDL.unload();
	}
}